package com.mxpio.erp.inventory.policy.impl;

import com.mxpio.erp.common.LotStatusUtil;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.InvFlow;
import com.mxpio.erp.common.inventory.entity.Lot;
import com.mxpio.erp.common.inventory.entity.WarehouseOrder;
import com.mxpio.erp.common.inventory.entity.WarehouseOrderLine;
import com.mxpio.erp.common.jpa.model.LotKey;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.purchase.entity.*;
import com.mxpio.erp.common.quality.entity.InQualityOrder;
import com.mxpio.erp.common.quality.entity.InQualityOrderLine;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpio.erp.inventory.policy.AbstractWoPolicy;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.security.util.SecurityUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * @Author : 吴盼盼
 * @Datetime : 2022/12/1 22:24
 * @Desc :
 * @Modor :  Modifytime:
 * @modDesc :采购订单对应仓单执行
 */
public class PurchaseWoPolicy extends AbstractWoPolicy {
    private List<OrderExcuteLineVo> orderExcuteVos;
    private OrderLineService orderLineService;
    public PurchaseWoPolicy(List<OrderExcuteLineVo> orderExcuteVos, OrderLineService orderLineService) {
        this.orderExcuteVos = orderExcuteVos;
        this.orderLineService = orderLineService;
    }

    public void execute(OrderContext context) {
        Order order = context.getEntity();
        if(order instanceof WarehouseOrder) {
            List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();
            List<InvFlow> invFlows = new ArrayList<>();

            Map<String, BigDecimal> sumQuantity = new HashMap<String, BigDecimal>();
            for(OrderExcuteLineVo vo : orderExcuteVos) {
                InvFlow invFlow = new InvFlow();
                String accessType = ((WarehouseOrder) order).getAccessType();
                invFlow.setAccessType(accessType);
                invFlow.setItemCode(vo.getItemCode());
                invFlow.setWhCode(((WarehouseOrder) order).getWhCode());
                // 批次控制
                if(OrderEnums.AccessType.IN.getCode().equals(accessType)) {
                    if(vo.getLotNo() == null) {
                        Lot newLot = context.getLotService().getNewLot(order, vo);
                        invFlow.setLotNo(newLot.getLotNo());
                        invFlow.setSubLotIndex(newLot.getSubLotIndex());
                    }else {
                        invFlow.setLotNo(vo.getLotNo());
                        String subLotIndex = StringUtils.isBlank(vo.getSubLotIndex())?"0":vo.getSubLotIndex();
                        invFlow.setSubLotIndex(subLotIndex);
                        LotKey lotKey = new LotKey();
                        lotKey.setLotNo(vo.getLotNo());
                        lotKey.setSubLotIndex(subLotIndex);
                        Lot dbLot = JpaUtil.getOne(Lot.class, lotKey);
                        if (dbLot==null){//保存批次
                            Lot lot = new Lot();
                            lot.setLotNo(vo.getLotNo());
                            lot.setLotStatus(LotStatusUtil.toBinaryString("0"));
                            lot.setSubLotIndex(subLotIndex);
                            JpaUtil.save(lot);
                        }
                    }
                }else {
                    if(vo.getLotNo() == null) {
                        context.addError("未分配批次");
                        break;
                    }else {
                        invFlow.setLotNo(vo.getLotNo());
                        invFlow.setSubLotIndex(vo.getSubLotIndex());
                    }
                }
                invFlow.setQuantity(vo.getQuantity());
                // 库存数量控制
                if(OrderEnums.AccessType.OUT.getCode().equals(accessType)) {
                    BigDecimal stock = context.getLotService().getStock(invFlow.getWhCode(), invFlow.getItemCode(), invFlow.getLotNo(),invFlow.getSubLotIndex(),false);
                    if(stock.compareTo(invFlow.getQuantity()) < 0) {
                        context.addError("物料：" + invFlow.getItemCode() + "库存不足");
                        break;
                    }
                }

                // 单据数量控制
                BigDecimal completeQuantity = context.getLotService().getMaxQuantityByWo(vo.getBizWoNo(), vo.getBizWoLineNo());
                BigDecimal currentQuan = sumQuantity.get(vo.getBizWoNo() + "#" + vo.getBizWoLineNo());
                if(currentQuan == null) {
                    BigDecimal maxQuantity = vo.getLineQuantity()==null?BigDecimal.ZERO:vo.getLineQuantity();
                    currentQuan = maxQuantity.subtract(completeQuantity).subtract(vo.getQuantity());
                }else {
                    currentQuan = currentQuan.subtract(vo.getQuantity());
                }
                if(currentQuan.compareTo(BigDecimal.ZERO) < 0) {
                    context.addError("物料：" + invFlow.getItemCode() + "超过最大执行数量");
                    break;
                }

                invFlow.setMemo(((WarehouseOrder) order).getMemo());
                invFlow.setOriginBizNo(((WarehouseOrder) order).getOriginBizNo());
                invFlow.setOriginBizType(((WarehouseOrder) order).getOriginBizType());
                invFlow.setOriginBizLineNo(vo.getBizOrderlineNo());
                invFlow.setWoBizNo(((WarehouseOrder) order).getBizNo());
                invFlow.setWoBizType(((WarehouseOrder) order).getWoType());
                invFlow.setWoBizLineNo(vo.getBizWoLineNo());
                invFlows.add(invFlow);
            }
            if(CollectionUtils.isEmpty(context.getErrors())) {
                JpaUtil.save(invFlows);
            }
        }else {
            context.addError("单据类型错误");
        }
    }

    @Override
    public OrderContext config(OrderContext context) {
        context.setOrderExcuteVos(orderExcuteVos);
        return context;
    }

    @Override
    public boolean beforeExecute(OrderContext context) {
        return true;
    }

    @Override
    public void afterExecute(OrderContext context) {
        if(CollectionUtils.isEmpty(context.getErrors())){
            Order wo = context.getEntity();
            if (judgeWOCompletion(context)){
                if(StringUtils.isBlank(wo.getExecutor())) {
                    wo.setExecuteTime(new Date());
                    wo.setExecutor(SecurityUtils.getLoginUsername());
                }
                wo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
                JpaUtil.update(wo);
            }else{
                if(OrderStatusEnums.OrderStatus.ORDERED.getStatusCode().equals(wo.getOrderStatus())||
                        OrderStatusEnums.OrderStatus.PLAN.getStatusCode().equals(wo.getOrderStatus())) {
                    wo.setOrderStatus(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
                    wo.setExecuteTime(new Date());
                    wo.setExecutor(SecurityUtils.getLoginUsername());
                    JpaUtil.update(wo);
                }
            }
            //判断订单订单执行，如果完成更新状态
            if (wo instanceof WarehouseOrder){
                WarehouseOrder warehouseOrder = (WarehouseOrder) wo;
                String originBizNo = warehouseOrder.getOriginBizNo();//源单编码
                //考虑手工新增的仓单，源单编码为空的情况
                if(StringUtils.isNotBlank(originBizNo)){
                    PurchaseOrder purchaseOrder = JpaUtil.getOne(PurchaseOrder.class, originBizNo);
                    boolean orderCompletionFlag = true;//采购订单是否完成
                    if (purchaseOrder!=null){
                        List<PurchaseOrderLine> purchaseOrderLines = JpaUtil.linq(PurchaseOrderLine.class).equal("bizNo", purchaseOrder.getBizNo()).list();
                        if (purchaseOrderLines.size()>0){
                            NoticeClassVo receivingNoticeClazz = new NoticeClassVo(ReceivingNotice.class, ReceivingNoticeLine.class);
                            NoticeClassVo rejectNoticeClazz = new NoticeClassVo(RejectNotice.class, RejectNoticeLine.class);
                            NoticeClassVo inQualityOrderClazz = new NoticeClassVo(InQualityOrder.class, InQualityOrderLine.class);//增加入库验收单 数据统计
                            List<NoticeClassVo> noticeClassVos = new ArrayList<>();
                            noticeClassVos.add(receivingNoticeClazz);
                            noticeClassVos.add(rejectNoticeClazz);
                            noticeClassVos.add(inQualityOrderClazz);
                            orderLineService.handleBizOrderLineQuantity(purchaseOrderLines, noticeClassVos, OrderEnums.AccessType.IN.getCode());

                            for (PurchaseOrderLine purchaseOrderLine:purchaseOrderLines){
                                BigDecimal quantity = purchaseOrderLine.getQuantity();//订单行数量
                                BigDecimal actualQuantity = purchaseOrderLine.getActualQuantity();//已执行数量
                                BigDecimal actualRejectQuantity = purchaseOrderLine.getActualRejectQuantity();//已执行退货数量
                                BigDecimal planQuantity = purchaseOrderLine.getPlanQuantity();//计划执行数量
                                BigDecimal planRejectQuantity = purchaseOrderLine.getPlanRejectQuantity();//计划退货数量
                                //判断订单行是否执行完成：1计划数量等于零，2已执行数量减去已执行退货数量等于订单行数量
                                if (planQuantity.compareTo(BigDecimal.ZERO)!=0
                                        ||planRejectQuantity.compareTo(BigDecimal.ZERO)!=0
                                        ||quantity.compareTo(actualQuantity.subtract(actualRejectQuantity))!=0){
                                    orderCompletionFlag = false;
                                    break;
                                }
                            }
                            if (orderCompletionFlag){
                                purchaseOrder.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());//完成
                                purchaseOrder.setExecuteTime(new Date());
                                JpaUtil.update(purchaseOrder);
                            }
                        }
                    }
                }
            }
        }
    }

    private boolean judgeWOCompletion(OrderContext context){//判断仓单是否已执行完毕
        Order order = context.getEntity();
        List<WarehouseOrderLine> lines = JpaUtil.linq(WarehouseOrderLine.class).equal("bizNo", order.getBizNo()).list();
        if (lines.size()>0){
            for (WarehouseOrderLine line:lines){
                BigDecimal completeQuantity = context.getLotService().getMaxQuantityByWo(line.getBizNo(), line.getLineNo());
                if (line.getQuantity().compareTo(completeQuantity)!=0){
                    return false;
                }
            }
        }else{
            return false;
        }
        return true;
    }
}
